package com.fzj.charging.order.mqtt;

import com.fzj.charging.common.pojo.JsonResult;
import com.fzj.charging.common.pojo.param.ChargingProcessParam;
import com.fzj.charging.common.pojo.param.GunStatusUpdateParam;
import com.fzj.charging.common.pojo.vo.ChargingProcessVO;
import com.fzj.charging.common.uiils.JacksonUtil;
import com.fzj.charging.order.common.ChargingConstants;
import com.fzj.charging.order.common.GunStatusConstants;
import com.fzj.charging.order.common.MqttConstants;
import com.fzj.charging.order.common.OrderStatusConstants;
import com.fzj.charging.order.pojo.dto.ChargingProcessDto;
import com.fzj.charging.order.pojo.dto.ChargingResultDto;
import com.fzj.charging.order.pojo.po.ChargingProcessPO;
import com.fzj.charging.order.pojo.po.OrderFailPO;
import com.fzj.charging.order.pojo.po.OrderSuccessPO;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.*;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Bean;

import java.util.Date;

@Slf4j
public class MqttConsumer implements MqttCallbackExtended {

    private MqttClient mqttClient;
    private MqttContext mqttContext;

    /* MqttConsumer是在MqttConfiguration被new出来的， 有被new出来的实例的，new 过的对象不会交给Spring容器管理
    直接注入的话报空指针异常
    @Autowired
    private OrderSuccessMapper orderSuccessMapper;
    @Autowired
    private OrderFailMapper orderFailMapper;
    @Autowired
    private DeviceClient deviceClient;*/
    /*因此采用构造器注入的方式，在new实例时将需要的属性传进来*/

    public MqttConsumer(){

    }

    /**
     * 构造器注入
     * @param mqttClient
     */
    public MqttConsumer(MqttClient mqttClient,MqttContext mqttContext){
        this.mqttClient = mqttClient;
        this.mqttContext = mqttContext;
    }
    @Override
    public void connectComplete(boolean reconnect, String serverURI) {
        log.debug("连接emqx完成，reconnect===>{},serverURI===>{}",reconnect,serverURI);
        String topicChargingResult = MqttConstants.TOPIC_CHARGING_RESULT;
        String topicChargingProcess = MqttConstants.TOPIC_CHARGING_PROCESS;
        try {
            mqttClient.subscribe(topicChargingResult);
            log.debug("订阅开始充电成功的消息，topic===>{}",topicChargingResult);
            mqttClient.subscribe(topicChargingProcess);
            log.debug("订阅来自设备充电数据的消息，topic===>{}",topicChargingProcess);
        } catch (MqttException e) {
            log.debug("异常信息===>",e);//可能需要重连
            //throw new RuntimeException(e);
        }
    }

    @Override
    public void connectionLost(Throwable cause) {
        log.warn("连接丢失，cause===>",cause);
    }

    @Override
    public void messageArrived(String topic, MqttMessage message) {
        log.debug("来自emqx订阅的消息到达,topic===>{},message===>{}",topic,message);
        if(MqttConstants.TOPIC_CHARGING_RESULT.equals(topic)){
            handleChargingResult(topic,message);
        }else if(MqttConstants.TOPIC_CHARGING_PROCESS.equals(topic)) {
            handleChargingProcess(topic,message);
        }
    }

    /**
     * 处理设备开始充电结果
     * @param topic emqx消息话题
     * @param message 消息
     */
    public void handleChargingResult(String topic, MqttMessage message){
        ChargingResultDto chargingResultDto = null;
        try {
            /*{
                "orderNo":"999",
                "gunId": 10,
                "pileId": 5,
                "result":"start_success"
               }*/
            chargingResultDto = JacksonUtil.fromJson(message.toString(), ChargingResultDto.class);
        } catch (Exception e) {
            log.error("设备发送的消息转为java对象失败，topic===>{},message===>{}",topic,message,e);
        }
        if(chargingResultDto!=null){
            String result = chargingResultDto.getResult();
            if(ChargingConstants.CHARGING_RESULT_SUCCESS.equals(result)){
                log.debug("设备发送开始充电成功的消息");
                log.debug("保存成功订单");
                OrderSuccessPO orderSuccessPO = new OrderSuccessPO();
                orderSuccessPO.setBillId(chargingResultDto.getOrderNo());
                orderSuccessPO.setGunId(chargingResultDto.getGunId());
                orderSuccessPO.setBillStatus(OrderStatusConstants.ORDER_STATUS_PROCESS);
                log.debug("保存充电成功的订单，订单信息{}",orderSuccessPO);
                int row = mqttContext.getOrderSuccessMapper().insert(orderSuccessPO);
                log.debug("保存充电成功的订单，订单信息{},数据库中受影响的行数{}",orderSuccessPO,row);

            }else{
                log.debug("设备发送开始充电失败的消息");
                log.debug("保存失败订单");
                OrderFailPO orderFailPO = new OrderFailPO();
                orderFailPO.setBillId(chargingResultDto.getOrderNo());
                orderFailPO.setGunId(chargingResultDto.getGunId());
                orderFailPO.setFailDesc("设备有响应，开始充电失败");
                log.debug("保存充电失败的订单，订单信息{}",orderFailPO);
                int row = mqttContext.getOrderFailMapper().insert(orderFailPO);
                log.debug("保存充电失败的订单，订单信息{}，数据库中受影响的行数{}",orderFailPO,row);

                log.debug("通知用户充电失败");//todo
                log.debug("给充电用户优惠券作为补偿");
                log.debug("修改枪的状态为故障");
                log.debug("通知维修人员维修");

                GunStatusUpdateParam gunStatusUpdateParam = new GunStatusUpdateParam();
                gunStatusUpdateParam.setGunId(chargingResultDto.getGunId());
                gunStatusUpdateParam.setStatus(GunStatusConstants.GUN_STATUS_FAIL);
                log.debug("更新枪的状态，gunStatusUpdateParam===>{}",gunStatusUpdateParam);
                JsonResult<Boolean> booleanJsonResult = mqttContext.getDeviceClient().updateGunStatus(gunStatusUpdateParam);
                log.debug("更新枪的状态，gunStatusUpdateParam===>{},返回结果===>{}",gunStatusUpdateParam,booleanJsonResult);

            }
        }
    }

    /**
     * 处理设备同步的充电数据
     * @param topic emqx消息话题
     * @param message 消息
     */
    public void handleChargingProcess(String topic, MqttMessage message){
        ChargingProcessDto chargingProcessDto = null;
        try {
            chargingProcessDto = JacksonUtil.fromJson(message.toString(), ChargingProcessDto.class);
        } catch (Exception e) {
            log.error("设备发送的充电进度消息转为java对象失败，topic===>{},message===>{}",topic,message,e);
        }
        if(chargingProcessDto!=null){
            log.debug("设备发送的充电进度消息转为java对象，topic===>{},message===>{},chargingProcessDto===>{}",topic,message,chargingProcessDto);
            //1.计算费用
            ChargingProcessParam chargingProcessParam = new ChargingProcessParam();
            BeanUtils.copyProperties(chargingProcessDto,chargingProcessParam);
            log.debug("订单服务调用计费服务的计费接口，参数：{}",chargingProcessParam);
            JsonResult<ChargingProcessVO> costResult = mqttContext.getCostClient().calculateCost(chargingProcessParam);
            log.debug("订单服务调用计费服务的计费接口，参数：{},计费计费结果：{}",chargingProcessParam,costResult);
            //2.保存数据到es
            saveChargingProcessToES(chargingProcessDto,costResult.getData());
            //3.向用户同步充电数据
            sendChargingProcessToUser(costResult.getData(), chargingProcessDto.getUserId());

        }
    }
    //保存充电数据到ES
    public void saveChargingProcessToES(ChargingProcessDto chargingProcessDto ,ChargingProcessVO chargingProcessVO){
        ChargingProcessPO chargingProcessPO = new ChargingProcessPO();
        chargingProcessPO.setId(new Date().getTime());
        BeanUtils.copyProperties(chargingProcessDto,chargingProcessPO);
        BeanUtils.copyProperties(chargingProcessVO,chargingProcessPO);
        log.debug("存储到es中的充电数据：{}",chargingProcessPO);
        mqttContext.getChargingProcessRepository().save(chargingProcessPO);
    }
    //向用户推送消息
    public void sendChargingProcessToUser(ChargingProcessVO chargingProcessVO,Integer userId){
        //String orderNo = chargingProcessVO.getOrderNo();
        //Integer userId = mqttContext.getOrderRepository().getSuccessOrder(orderNo).getUserId();
        mqttContext.getWebSocketServer().sendMessage(userId,JacksonUtil.toJson(chargingProcessVO));
    }

    @Override
    public void deliveryComplete(IMqttDeliveryToken token) {
        log.debug("消息投递完成，token====>{}",token);
    }
}
